create or replace package m4o_package_generator as

  type argument_t is record (
    name      varchar2(4000),
    data_type varchar2(4000),
    in_out    varchar2(10)
  );
  type argument_tt  is table of argument_t  index by binary_integer;

  type attribute_tt is table of m4o_package_attr.value%type
                       index by m4o_package_attr.name%type;
  type part_t       is record (
    is_public           m4o_package_part.is_public         %type,
    type_id             m4o_package_part.type_id           %type,
    sourcecode          m4o_package_part.sourcecode        %type,
    name                m4o_package_part.name              %type,
    return_type         m4o_package_part.return_type       %type,
    arguments           m4o_package_part.arguments         %type,
    local_declarations  m4o_package_part.local_declarations%type,
    attributes          attribute_tt,
    parsed_arguments    argument_tt
  );
  type part_tt      is table of part_t index by pls_integer;
  type package_t    is record (
    name                m4o_package_defn.name              %type,
    in_schema           m4o_package_defn.in_schema         %type,
    authid_current_user m4o_package_defn.authid_current_user%type,
    attributes          attribute_tt,
    parts               part_tt
  );

  -- ===========================================================================
  C_DECLARATION_TYPEID constant number := 1;
  C_PROCEDURE_TYPEID   constant number := 2;
  C_FUNCTION_TYPEID    constant number := 3;
  C_INIT_TYPEID        constant number := 4;

  -- ===========================================================================
  p_package package_t;
  p_part_id binary_integer;

  -- ===========================================================================
  -- starts a new package definition.
  procedure package_begin(
    i_schema_and_name           in varchar2,
    i_authid_current_user       in varchar2,
    i_current_schema            in varchar2);
  -- ===========================================================================
  -- finishes the definition of the current package and generates code.
  procedure package_end;
  -- ===========================================================================
  -- sets a package or package part attribute
  procedure set_attr(
    i_name                      in varchar2,
    i_value                     in varchar2);
  -- ===========================================================================
  -- starts a new package part definition.
  -- this finishes the definition of a previously started package part.
  procedure package_part_begin(
    i_type_name                 in varchar2,
    i_name_and_visibility       in varchar2 := null,
    i_return_type               in varchar2 := null,
    i_arguments                 in varchar2 := null);
  -- ===========================================================================
  -- sets local declarations of current package part
  procedure set_local_declarations(
    i_local_declarations        in varchar2);
  -- ===========================================================================
  -- sets source code of current package part
  procedure set_sourcecode(
    i_sourcecode                in varchar2);
  -- ===========================================================================
  procedure package_part_end;
  -- ===========================================================================
  -- helper for aspect code: return if attribute i_name exists for current part
  -- or at package level
  function attribute_exists(
    i_name                      in varchar2)
  return boolean;
  -- ===========================================================================
  -- helper for aspect code: return value of attribute i_name at part level or
  -- at package level (if it does not exist at part level).
  -- returns null if attribute was not found.
  function get_attribute(
    i_name                      in varchar2)
  return varchar2;
end;
/
